package device;

import communication.Communicator;
import communication.definitions.DeviceType;
import communication.definitions.Message;
import communication.definitions.ReceivedFunction;
import communication.definitions.TransmitableFunction;
import communication.exceptions.InvalidArgumentsException;
import communication.exceptions.InvalidFunctionException;

/**
 * A <code>Sensor</code> is a subclass of <code>Device</code> which implements
 * two common functions which most sensors will need to implement: REQUEST_VALUE
 * and SET_VALUE.
 * <p>
 * When extending this class <code>setValue(byte[] args)</code> will need to be
 * implemented and <code>super.receiveFunction</code> <i>must</i> be called from
 * inside the overridden <code>receiveFunction</code>.
 * 
 * @author Peter Kalauskas
 */
public abstract class Sensor extends Device {
	private int value;

	/**
	 * Constructs a new sensor with the given type and id. Value will be 0 by
	 * default.
	 * 
	 * @param type
	 *            the type of this device
	 * @param id
	 *            the id of this device. When possible this should be something
	 *            meaningful, such as an ADC channel since it will always be
	 *            sent to the robot as an argument.
	 * @param comm
	 *            the communicator which this device will use
	 */
	public Sensor(DeviceType type, byte id, Communicator comm) {
		super(type, id, comm);
		value = 0;
	}

	/**
	 * Returns the raw sensor value stored in this object. This will not request
	 * an updated value from the robot.
	 * 
	 * @return the stored raw sensor.
	 */
	public int getValue() {
		return value;
	}

	/**
	 * Sets the raw value stored in this object.
	 * 
	 * @param value
	 *            the value to store in this object.
	 */
	protected void setValue(int value) {
		this.value = value;
	}

	/**
	 * Sends a REQUEST_VALUE message to the given.
	 */
	public void requestValue() {
		try {
			comm.send(new Message(this, TransmitableFunction.REQUEST_VALUE,
					new byte[0]));
		} catch (InvalidArgumentsException e) {
			// This should never happen unless REQUEST_VALUE is changed
			e.printStackTrace();
		}
	}

	/**
	 * Calls the <code>setValue</code> function when a SET_VALUE message is
	 * received.
	 */
	public void receiveFunction(ReceivedFunction f, byte[] args)
			throws InvalidArgumentsException, InvalidFunctionException {
		super.receiveFunction(f, args);
		switch (f) {
		case SET_VALUE:
			setValue(args);
			break;
		default:
			throw new InvalidFunctionException("Function " + f
					+ " is not implemented for device type " + getType());
		}
	}

	/**
	 * Sets the raw value of this sensor.
	 * 
	 * @param args
	 * @throws InvalidArgumentsException
	 *             if the size of the args array longer or shorter than
	 *             expected.
	 */
	protected abstract void setValue(byte[] args)
			throws InvalidArgumentsException;
}
